﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using ShredTheLog.Api.DataContracts.TextChat;
using System.Diagnostics.Contracts;
using ShredTheLog.Api;

namespace ShredTheLog.Model
{
    [XmlRoot("UPDs")]
    public sealed class TextChatUpdates
    {
        [XmlAttribute("LUPD")]
        public int LastUpdate { get; set; }

        [XmlElement("Error")]
        public object[] Error { get; set; }

        [XmlElement("Disconnect")]
        public object[] Disconnect { get; set; }

        [XmlElement("UPD")]
        public TextChatUpdate[] Items { get; set; }

        private static readonly object[] EmptyArray = new object[0];

        public IEnumerable<Exception> Exceptions
        {
            get
            {
                var result =
                    (from e in Error != null ? Error : EmptyArray select (Exception)new ErrorException()).Concat
                    (from e in Disconnect != null ? Disconnect : EmptyArray select (Exception)new DisconnectException());
                return result;
            }
        }

        public class ErrorException : Exception
        {
            public ErrorException() : base("Server has returned «Error» error code.") { }
            protected ErrorException(SerializationInfo info, StreamingContext context) : base(info, context) { }
        }

        public class DisconnectException : Exception
        {
            public DisconnectException() : base("Server has returned «Disconnect» error code.") { }
            protected DisconnectException(SerializationInfo info, StreamingContext context) : base(info, context) { }
        }
    }

    [XmlRoot("UPD")]
    public sealed class TextChatUpdate
    {
        [XmlAttribute("ID")]
        public int Id { get; set; }

        [XmlElement("U")]
        public AddUserUpdate AddUser { get; set; }

        [XmlElement("DU")]
        public DropUserUpdate DropUser { get; set; }

        [XmlElement("ER")]
        public EnterRoomUpdate EnterRoom { get; set; }

        [XmlElement("FP")]
        public FlashPenUpdate FlashPen { get; set; }

        [XmlElement("M")]
        public AddMessageUpdate AddMessage { get; set; }

        [XmlElement("C")]
        public PrivateChatRequestUpdate PrivateChatRequest { get; set; }

        [XmlElement("CR")]
        public SysMessageUpdate SysMessage { get; set; }

        public ITextChatUpdate UpdateAction
        {
            get
            {
                Contract.Ensures(Contract.Result<ITextChatUpdate>() != null);

                var result = AddUser ?? DropUser ?? EnterRoom ?? FlashPen ?? AddMessage ?? PrivateChatRequest ?? (ITextChatUpdate)SysMessage;
                Contract.Assume(result != null);
                return result;
            }
        }
    }
}
